import { describe, should } from '@paulmillr/jsbt/test.js';
import { deepStrictEqual as eql } from 'node:assert';
import * as mod from '../src/abstract/modular.ts';
import * as poseidon from '../src/abstract/poseidon.ts';
import * as stark from './_poseidon.helpers.ts';
import { json } from './utils.ts';
const vecp = json('./vectors/poseidon.json');

const parseArrBig = (arr) => arr.map((n) => BigInt(n));

describe('Stark', () => {
  should('poseidonMdsMatrixUnsafe', () => {
    const matrix = [
      [
        2778560475384578201077246683568670693743746494974613838537993780462451025202n,
        1175299404131241652930097281601393692628174430208909163156444576599667748918n,
        459930634481240293374476654621049426021644833445120509139335338093973616187n,
      ],
      [
        2699370377471722242958186781613316939129713429759631049128040020458992590651n,
        1488831960940040807419416081499284128899207850625157044437836107358246188803n,
        3405112981980800875534081635548548562399171531483475155039499736396630179833n,
      ],

      [
        1860070716810022053527433635909648527418980081585070357136946388030401399342n,
        2606527819893847364468965441606872534271438365089422719512470850627617054272n,
        2715867691630559973784374069384091521307896505826088878858115800121387149186n,
      ],
    ];
    eql(stark._poseidonMDS(stark.Fp251, 'HadesMDS', 3, 0), matrix);
  });

  should('HadesPermutation', () => {
    eql(
      stark.poseidonSmall([
        4379311784651118086770398084575492314150568148003994287303975907890254409956n,
        5329163686893598957822497554130545759427567507701132391649270915797304266381n,
        1081797873147645298856697595691862435558345225505029083672323747888463248125n,
      ]),
      [
        1342232677189718451682683203787286758407058155581807117466384919996430343159n,
        380853961496438693334706417244065195303131974442781224856980145160981376662n,
        1919212703304954644851339421413808305076993030243665926017858381407659820613n,
      ]
    );
  });
  should('HadesPermutation (custom)', () => {
    const h = stark.poseidonCreate({
      Fp: stark.Fp251,
      rate: 2,
      capacity: 1,
      roundsFull: 8,
      roundsPartial: 83,
    });
    eql(
      h([
        4379311784651118086770398084575492314150568148003994287303975907890254409956n,
        5329163686893598957822497554130545759427567507701132391649270915797304266381n,
        1081797873147645298856697595691862435558345225505029083672323747888463248125n,
      ]),
      [
        2864461397224564530993577865807718592436235694918699912757414692654057505365n,
        1576206983934669422583425346343473837630736957734769961428118554039862202613n,
        1607006208879950753054674913136990521997740361932184292107790666308092455675n,
      ]
    );
  });
  should('HadesPermutation (custom, Fp253)', () => {
    const h = stark.poseidonCreate({
      Fp: stark.Fp253,
      rate: 2,
      capacity: 1,
      roundsFull: 8,
      roundsPartial: 83,
    });
    eql(
      h([
        4379311784651118086770398084575492314150568148003994287303975907890254409956n,
        5329163686893598957822497554130545759427567507701132391649270915797304266381n,
        1081797873147645298856697595691862435558345225505029083672323747888463248125n,
      ]),
      [
        11142411210283675631592374649001218595612035205233832049083369488791454026844n,
        98304838055259883374145304326851527594402230455144399354815642835291000581n,
        8643534790068701259242695637167859384191499281344739826454631748110172472997n,
      ]
    );
  });
  should('PoseidonHash', () => {
    eql(
      stark.poseidonHash(
        4379311784651118086770398084575492314150568148003994287303975907890254409956n,
        5329163686893598957822497554130545759427567507701132391649270915797304266381n
      ),
      2457757238178986673695038558497063891521456354791980183317105434323761563347n
    );
  });
  should('PoseidonHash (custom)', () => {
    const h = stark.poseidonCreate({
      Fp: stark.Fp251,
      rate: 2,
      capacity: 1,
      roundsFull: 8,
      roundsPartial: 83,
    });
    eql(
      stark.poseidonHash(
        4379311784651118086770398084575492314150568148003994287303975907890254409956n,
        5329163686893598957822497554130545759427567507701132391649270915797304266381n,
        h
      ),
      654164301216498483748450956182386165976155551413834652546305861430119544536n
    );
  });
  should('PoseidonHash (custom, Fp253)', () => {
    const h = stark.poseidonCreate({
      Fp: stark.Fp253,
      rate: 2,
      capacity: 1,
      roundsFull: 8,
      roundsPartial: 83,
    });
    eql(
      stark.poseidonHash(
        4379311784651118086770398084575492314150568148003994287303975907890254409956n,
        5329163686893598957822497554130545759427567507701132391649270915797304266381n,
        h
      ),
      9557424461253897982213839283192966960594440725760392861778010931094267239786n
    );
  });
});
// Official vectors:
// https://extgit.iaik.tugraz.at/krypto/hadeshash/-/blob/master/code/test_vectors.txt

should('poseidonperm_x5_255_3', () => {
  const Fp = mod.Field(
    BigInt('0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001')
  );

  const mds = [
    [
      0x3d955d6c02fe4d7cb500e12f2b55eff668a7b4386bd27413766713c93f2acfcdn,
      0x3798866f4e6058035dcf8addb2cf1771fac234bcc8fc05d6676e77e797f224bfn,
      0x2c51456a7bf2467eac813649f3f25ea896eac27c5da020dae54a6e640278fda2n,
    ],
    [
      0x20088ca07bbcd7490a0218ebc0ecb31d0ea34840e2dc2d33a1a5adfecff83b43n,
      0x1d04ba0915e7807c968ea4b1cb2d610c7f9a16b4033f02ebacbb948c86a988c3n,
      0x5387ccd5729d7acbd09d96714d1d18bbd0eeaefb2ddee3d2ef573c9c7f953307n,
    ],
    [
      0x1e208f585a72558534281562cad89659b428ec61433293a8d7f0f0e38a6726acn,
      0x0455ebf862f0b60f69698e97d36e8aafd4d107cae2b61be1858b23a3363642e0n,
      0x569e2c206119e89455852059f707370e2c1fc9721f6c50991cedbbf782daef54n,
    ],
  ];

  const t = 3;

  const roundConstants = poseidon.splitConstants(vecp.st1.map(BigInt), t);

  const poseidon_x5_255_3 = poseidon.poseidon({
    Fp,
    t,
    roundsFull: 8,
    roundsPartial: 57,
    sboxPower: 5,
    mds,
    roundConstants,
  });
  eql(
    poseidon_x5_255_3([
      0x0000000000000000000000000000000000000000000000000000000000000000n,
      0x0000000000000000000000000000000000000000000000000000000000000001n,
      0x0000000000000000000000000000000000000000000000000000000000000002n,
    ]),
    [
      0x28ce19420fc246a05553ad1e8c98f5c9d67166be2c18e9e4cb4b4e317dd2a78an,
      0x51f3e312c95343a896cfd8945ea82ba956c1118ce9b9859b6ea56637b4b1ddc4n,
      0x3b2b69139b235626a0bfb56c9527ae66a7bf486ad8c11c14d1da0c69bbe0f79an,
    ]
  );
});

should('poseidonperm_x5_255_5', () => {
  const Fp = mod.Field(0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001n);
  const t = 5;

  const mds = [
    [
      0x354423b163d1078b0dd645be56316e34a9b98e52dcf9f469be44b108be46c107n,
      0x44778737e8bc1154aca1cd92054a1e5b83808403705f7d54da88bbd1920e1053n,
      0x5872eefb5ab6b2946556524168a2aebb69afd513a2fff91e50167b1f6e4055e0n,
      0x43dff85b25129835819bc8c95819f1a34136f6114e900cd3656e1b9e0e13f86an,
      0x07803d2ffe72940596803f244ac090a9cf2d3616546520bc360c7eed0b81cbf8n,
    ],
    [
      0x45d6bc4b818e2b9a53e0e2c0a08f70c34167fd8128e05ac800651ddfee0932d1n,
      0x08317abbb9e5046b22dfb79e64c8184855107c1d95dddd2b63ca10dddea9ff1an,
      0x1bb80eba77c5dcffafb55ccba4ae39ac8f94a054f2a0ee3006b362f709d5e470n,
      0x038e75bdcf8be7fd3a1e844c4de7333531bbd5a8d2c3779627df88e7480e7c5cn,
      0x2dd797a699e620ea6b31b91ba3fad4a82f40cffb3e8a30c0b7a546ff69a9002bn,
    ],
    [
      0x4b906f9ee339b196e958e3541b555b4b53e540a113b2f1cabba627be16eb5608n,
      0x605f0c707b82ef287f46431f9241fe4acf0b7ddb151803cbcf1e7bbd27c3e974n,
      0x100c514bf38f6ff10df1c83bb428397789cfff7bb0b1280f52343861e8c8737en,
      0x2d40ce8af8a252f5611701c3d6b1e517161d0549ef27f443570c81fcdfe3706bn,
      0x3e6418bdf0313f59afc5f40b4450e56881110ea9a0532e8092efb06a12a8b0f1n,
    ],
    [
      0x71788bf7f6c0cebae5627c5629d012d5fba52428d1f25cdaa0a7434e70e014d0n,
      0x55cc73296f7e7d26d10b9339721d7983ca06145675255025ab00b34342557db7n,
      0x0f043b29be2def73a6c6ec92168ea4b47bc9f434a5e6b5d48677670a7ca4d285n,
      0x62ccc9cdfed859a610f103d74ea04dec0f6874a9b36f3b4e9b47fd73368d45b4n,
      0x55fb349dd6200b34eaba53a67e74f47d08e473da139dc47e44df50a26423d2d1n,
    ],
    [
      0x45bfbe5ed2f4a01c13b15f20bba00ff577b1154a81b3f318a6aff86369a66735n,
      0x6a008906685587af05dce9ad2c65ea1d42b1ec32609597bd00c01f58443329efn,
      0x004feebd0dbdb9b71176a1d43c9eb495e16419382cdf7864e4bce7b37440cd58n,
      0x09f080180ce23a5aef3a07e60b28ffeb2cf1771aefbc565c2a3059b39ed82f43n,
      0x2f7126ddc54648ab6d02493dbe9907f29f4ef3967ad8cd609f0d9467e1694607n,
    ],
  ];

  const roundConstants = poseidon.splitConstants(vecp.st2.map(BigInt), t);

  const poseidon_x5_255_5 = poseidon.poseidon({
    Fp,
    t,
    roundsFull: 8,
    roundsPartial: 60,
    sboxPower: 5,
    mds,
    roundConstants,
  });

  eql(
    poseidon_x5_255_5([
      0x0000000000000000000000000000000000000000000000000000000000000000n,
      0x0000000000000000000000000000000000000000000000000000000000000001n,
      0x0000000000000000000000000000000000000000000000000000000000000002n,
      0x0000000000000000000000000000000000000000000000000000000000000003n,
      0x0000000000000000000000000000000000000000000000000000000000000004n,
    ]),
    [
      0x2a918b9c9f9bd7bb509331c81e297b5707f6fc7393dcee1b13901a0b22202e18n,
      0x65ebf8671739eeb11fb217f2d5c5bf4a0c3f210e3f3cd3b08b5db75675d797f7n,
      0x2cc176fc26bc70737a696a9dfd1b636ce360ee76926d182390cdb7459cf585cen,
      0x4dc4e29d283afd2a491fe6aef122b9a968e74eff05341f3cc23fda1781dcb566n,
      0x03ff622da276830b9451b88b85e6184fd6ae15c8ab3ee25a5667be8592cce3b1n,
    ]
  );
});

should('poseidonperm_x5_254_3', () => {
  const Fp = mod.Field(0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001n);
  const t = 3;

  const mds = [
    [
      0x109b7f411ba0e4c9b2b70caf5c36a7b194be7c11ad24378bfedb68592ba8118bn,
      0x16ed41e13bb9c0c66ae119424fddbcbc9314dc9fdbdeea55d6c64543dc4903e0n,
      0x2b90bba00fca0589f617e7dcbfe82e0df706ab640ceb247b791a93b74e36736dn,
    ],
    [
      0x2969f27eed31a480b9c36c764379dbca2cc8fdd1415c3dded62940bcde0bd771n,
      0x2e2419f9ec02ec394c9871c832963dc1b89d743c8c7b964029b2311687b1fe23n,
      0x101071f0032379b697315876690f053d148d4e109f5fb065c8aacc55a0f89bfan,
    ],
    [
      0x143021ec686a3f330d5f9e654638065ce6cd79e28c5b3753326244ee65a1b1a7n,
      0x176cc029695ad02582a70eff08a6fd99d057e12e58e7d7b6b16cdfabc8ee2911n,
      0x19a3fc0a56702bf417ba7fee3802593fa644470307043f7773279cd71d25d5e0n,
    ],
  ];

  const roundConstants = poseidon.splitConstants(vecp.st3.map(BigInt), t);

  const poseidon_x5_254_3 = poseidon.poseidon({
    Fp,
    t,
    roundsFull: 8,
    roundsPartial: 57,
    sboxPower: 5,
    mds,
    roundConstants,
  });

  eql(
    poseidon_x5_254_3([
      0x0000000000000000000000000000000000000000000000000000000000000000n,
      0x0000000000000000000000000000000000000000000000000000000000000001n,
      0x0000000000000000000000000000000000000000000000000000000000000002n,
    ]),
    [
      0x115cc0f5e7d690413df64c6b9662e9cf2a3617f2743245519e19607a4417189an,
      0x0fca49b798923ab0239de1c9e7a4a9a2210312b6a2f616d18b5a87f9b628ae29n,
      0x0e7ae82e40091e63cbd4f16a6d16310b3729d4b6e138fcf54110e2867045a30cn,
    ]
  );
});

should('poseidonperm_x5_254_5', () => {
  const Fp = mod.Field(0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001n);
  const t = 5;

  const mds = [
    [
      0x251e7fdf99591080080b0af133b9e4369f22e57ace3cd7f64fc6fdbcf38d7da1n,
      0x25fb50b65acf4fb047cbd3b1c17d97c7fe26ea9ca238d6e348550486e91c7765n,
      0x293d617d7da72102355f39ebf62f91b06deb5325f367a4556ea1e31ed5767833n,
      0x104d0295ab00c85e960111ac25da474366599e575a9b7edf6145f14ba6d3c1c4n,
      0x0aaa35e2c84baf117dea3e336cd96a39792b3813954fe9bf3ed5b90f2f69c977n,
    ],
    [
      0x2a70b9f1d4bbccdbc03e17c1d1dcdb02052903dc6609ea6969f661b2eb74c839n,
      0x281154651c921e746315a9934f1b8a1bba9f92ad8ef4b979115b8e2e991ccd7an,
      0x28c2be2f8264f95f0b53c732134efa338ccd8fdb9ee2b45fb86a894f7db36c37n,
      0x21888041e6febd546d427c890b1883bb9b626d8cb4dc18dcc4ec8fa75e530a13n,
      0x14ddb5fada0171db80195b9592d8cf2be810930e3ea4574a350d65e2cbff4941n,
    ],
    [
      0x2f69a7198e1fbcc7dea43265306a37ed55b91bff652ad69aa4fa8478970d401dn,
      0x001c1edd62645b73ad931ab80e37bbb267ba312b34140e716d6a3747594d3052n,
      0x15b98ce93e47bc64ce2f2c96c69663c439c40c603049466fa7f9a4b228bfc32bn,
      0x12c7e2adfa524e5958f65be2fbac809fcba8458b28e44d9265051de33163cf9cn,
      0x2efc2b90d688134849018222e7b8922eaf67ce79816ef468531ec2de53bbd167n,
    ],
    [
      0x0c3f050a6bf5af151981e55e3e1a29a13c3ffa4550bd2514f1afd6c5f721f830n,
      0x0dec54e6dbf75205fa75ba7992bd34f08b2efe2ecd424a73eda7784320a1a36en,
      0x1c482a25a729f5df20225815034b196098364a11f4d988fb7cc75cf32d8136fan,
      0x2625ce48a7b39a4252732624e4ab94360812ac2fc9a14a5fb8b607ae9fd8514an,
      0x07f017a7ebd56dd086f7cd4fd710c509ed7ef8e300b9a8bb9fb9f28af710251fn,
    ],
    [
      0x2a20e3a4a0e57d92f97c9d6186c6c3ea7c5e55c20146259be2f78c2ccc2e3595n,
      0x1049f8210566b51faafb1e9a5d63c0ee701673aed820d9c4403b01feb727a549n,
      0x02ecac687ef5b4b568002bd9d1b96b4bef357a69e3e86b5561b9299b82d69c8en,
      0x2d3a1aea2e6d44466808f88c9ba903d3bdcb6b58ba40441ed4ebcf11bbe1e37bn,
      0x14074bb14c982c81c9ad171e4f35fe49b39c4a7a72dbb6d9c98d803bfed65e64n,
    ],
  ];

  const roundConstants = poseidon.splitConstants(vecp.st4.map(BigInt), t);

  const poseidon_x5_254_5 = poseidon.poseidon({
    Fp,
    t,
    roundsFull: 8,
    roundsPartial: 60,
    sboxPower: 5,
    mds,
    roundConstants,
  });

  eql(
    poseidon_x5_254_5([
      0x0000000000000000000000000000000000000000000000000000000000000000n,
      0x0000000000000000000000000000000000000000000000000000000000000001n,
      0x0000000000000000000000000000000000000000000000000000000000000002n,
      0x0000000000000000000000000000000000000000000000000000000000000003n,
      0x0000000000000000000000000000000000000000000000000000000000000004n,
    ]),
    [
      0x299c867db6c1fdd79dcefa40e4510b9837e60ebb1ce0663dbaa525df65250465n,
      0x1148aaef609aa338b27dafd89bb98862d8bb2b429aceac47d86206154ffe053dn,
      0x24febb87fed7462e23f6665ff9a0111f4044c38ee1672c1ac6b0637d34f24907n,
      0x0eb08f6d809668a981c186beaf6110060707059576406b248e5d9cf6e78b3d3en,
      0x07748bc6877c9b82c8b98666ee9d0626ec7f5be4205f79ee8528ef1c4a376fc7n,
    ]
  );
});
// Startadperm is unsupported, since it is non prime field

describe('PoseidonSponge', () => {
  // TODO: add more tests? There maybe some more edge-cases here.
  describe('Cross-test: ProvableHQ/snarkVM (aleo)', () => {
    // NOTE: there is no generation code, because it required patching a lot of crates to expose private APIs.
    const Fp = mod.Field(
      8444461749428370424248824938781546531375899335154063827935233455917409239041n,
      undefined,
      false
    );
    should('Grain', () => {
      const { mds, roundConstants } = poseidon.grainGenConstants({
        Fp,
        t: 2 + 1,
        roundsFull: 8,
        roundsPartial: 31,
      });
      eql(mds, [
        [
          6093452032963406658309134825240609333033222270199073508119142384975416392638n,
          5968273173562867837210008744966745230923761158428968101807573098840850097286n,
          1100466639266852149977689148055725793531897994956807001704693611715839541982n,
        ],
        [
          3160983601532844171864802850648492289862147997874094785600836495095965353712n,
          2338351297827692414112631814274572996809824929139580588221558887342663769892n,
          3177005087903404343485399282920555615020488967881372266904325860698809358885n,
        ],
        [
          2285176219817854683696635383059984246218458246545520061123961933072089703485n,
          84377861777946561525373172505381054389617879929776365352216307785104476701n,
          8280884008678095605415834125731826663585461281789631237939546251146561093166n,
        ],
      ]);
      eql(roundConstants, vecp.aleo_grain_roundConstants.map(parseArrBig));
    });
    should('rate=2 capacity=1', () => {
      const rate = 2;
      const capacity = 1;
      const { mds, roundConstants } = poseidon.grainGenConstants({
        Fp,
        t: rate + capacity,
        roundsFull: 8,
        roundsPartial: 31,
      });
      const sponge = poseidon.poseidonSponge({
        Fp,
        rate,
        capacity,
        sboxPower: 17,
        mds,
        roundConstants,
        roundsFull: 8,
        roundsPartial: 31,
      });
      const inputs = [
        3801852864665033841774715284518384682376829752661853198612247855579120198106n,
        8354898322875240371401674517397790035008442020361740574117886421279083828480n,
        4810388512520169167962815122521832339992376865086300759308552937986944510606n,
        6901184695964460143517399399785179769303979738604374595034454667750561389951n,
        4569986992907167903298094880801044988451682407606958090985246015539197576880n,
        1659013762488693582855478522957329119959921484276233144739847127722099836592n,
        5873855434568679481242703448145783278614510745576299549051743569349492512978n,
        8126778056340108742720298710864854335340160587591670858399923536543205675034n,
        7146400424093292796305326969877508376475248301146079897262686723570477471481n,
        4313136198840596462591029581810482612339281338296848099835538102215716458507n,
        6282620155184535925059193831765937196673297460411024331501133151513540140819n,
      ];
      // absorb(3);squeeze(2)
      const s1 = sponge();
      s1.absorb(inputs.slice(0, 3));
      eql(s1.squeeze(2), [
        5528124139915370778497908783898741139153574846551220495957672211442474308196n,
        2420619180129571354470214721153552874135214293988121929445742760421351812085n,
      ]);
      // absorb(0);squeeze(3);
      const s2 = sponge();
      s2.absorb([]);
      eql(s2.squeeze(3), [
        933733638681902971366883597456330506627704278683959399109999726127624278648n,
        7947296799800775327938262145036085767367577952489561846300684316471048325151n,
        8176130403051036805322877644409334453960127468352705414400032728890307490770n,
      ]);
      // absorb(2);absorb(1);squeeze(2) == absorb(3);squeeze(2)
      const s3 = sponge();
      s3.absorb(inputs.slice(0, 2));
      s3.absorb([inputs[2]]);
      eql(s3.squeeze(2), [
        5528124139915370778497908783898741139153574846551220495957672211442474308196n,
        2420619180129571354470214721153552874135214293988121929445742760421351812085n,
      ]);
      // absorb(3);squeeze(1);squeeze(1)
      const s4 = sponge();
      s4.absorb(inputs.slice(0, 3));
      eql(s4.squeeze(1), [
        5528124139915370778497908783898741139153574846551220495957672211442474308196n,
      ]);
      eql(s4.squeeze(1), [
        2420619180129571354470214721153552874135214293988121929445742760421351812085n,
      ]);
      // absorb(11);squeeze(2);
      const s5 = sponge();
      s5.absorb(inputs);
      eql(s5.squeeze(2), [
        26553393923456202663144989311824517705110159271577366819618683341297406966n,
        7016672899849811490358640818454305819532854937834096463294677928554860101232n,
      ]);
      // squeeze(2);
      const s6 = sponge();
      eql(s6.squeeze(2), [
        933733638681902971366883597456330506627704278683959399109999726127624278648n,
        7947296799800775327938262145036085767367577952489561846300684316471048325151n,
      ]);
      // absobr(3); squeeze(2); absorb(3); squeeze(2);
      const s7 = sponge();
      s7.absorb(inputs.slice(0, 3));
      eql(s7.squeeze(2), [
        5528124139915370778497908783898741139153574846551220495957672211442474308196n,
        2420619180129571354470214721153552874135214293988121929445742760421351812085n,
      ]);
      s7.absorb(inputs.slice(3, 6));
      eql(s7.squeeze(2), [
        5588447626321408884036227149970492957886517571060242219931529251408668452862n,
        3785030165774957122639768627564213246094662307916570387367075908156611788837n,
      ]);
      // absorb(3);squeeze(0);absorb(3);squeeze(2)
      const s8 = sponge();
      s8.absorb(inputs.slice(0, 3));
      eql(s8.squeeze(0), []);
      s8.absorb(inputs.slice(3, 6));
      eql(s8.squeeze(2), [
        6470185464793428861582857521285696840123874904819191690530167712863056078884n,
        678032572423041477979964450039774208343357930887800030208970759669150733000n,
      ]);
      // absorb(3);squeeze(2);absorb(0);squeeze(2)
      const s9 = sponge();
      s9.absorb(inputs.slice(0, 3));
      eql(s9.squeeze(2), [
        5528124139915370778497908783898741139153574846551220495957672211442474308196n,
        2420619180129571354470214721153552874135214293988121929445742760421351812085n,
      ]);
      s9.absorb([]);
      eql(s9.squeeze(2), [
        2492034033820692577660772442004599604877416958552504035222255780764492626637n,
        3219631157933579149223017804239080280224882035858525007265472051339661711735n,
      ]);
      // absorb(1);squeeze(2);
      const s10 = sponge();
      s10.absorb(inputs.slice(0, 1));
      eql(s10.squeeze(2), [
        7644420660423831885731682109272695821257057596295339585794759757016078689547n,
        3859905479154147442482078504776928705199511809151329003321175729702391795042n,
      ]);
      // absobr(3); squeeze(1); absorb(3); squeeze(1);
      const s11 = sponge();
      s11.absorb(inputs.slice(0, 3));
      eql(s11.squeeze(1), [
        5528124139915370778497908783898741139153574846551220495957672211442474308196n,
      ]);
      s11.absorb(inputs.slice(3, 6));
      eql(s11.squeeze(1), [
        5588447626321408884036227149970492957886517571060242219931529251408668452862n,
      ]);
    });
    // NOTE: cannot test original with capacity=2 since parameter generation forces capacity=1
  });
  describe('arkworks', () => {
    const Fp =
      mod.Field(52435875175126190479447740508185965837690552500527637822603658699938581184513n);
    should('Grain', () => {
      const { mds, roundConstants } = poseidon.grainGenConstants({
        Fp,
        t: 2 + 1,
        roundsFull: 8,
        roundsPartial: 31,
      });
      eql(mds, [
        [
          26017457457808754696901916760153646963713419596921330311675236858336250747575n,
          3639683834202950894361433288826233741561896854900895753431766653813988568616n,
          10953049236150794552744618049606510050375451747770323040062198642862470543754n,
        ],
        [
          3183018564195653675423838894051554438478916606994940049401425837017785750901n,
          36645976574820377700902571812165679932959923609739614084701394317315987922520n,
          13667371158342095156950515738523876561616032888638618897036472097355505737588n,
        ],
        [
          18132402185753749320702654985017413608679949734954283116304111549041393007832n,
          39402135980459413670418975061282080453597554822712441131542254198170946062014n,
          13521929589998302886085098386422384259477894224415500174630722069318478944823n,
        ],
      ]);
      eql(roundConstants, vecp.arkworks_grain_roundConstants.map(parseArrBig));
    });
    should('rate=2 capacity=1', () => {
      const rate = 2;
      const capacity = 1;
      const { mds, roundConstants } = poseidon.grainGenConstants({
        Fp,
        t: rate + capacity,
        roundsFull: 8,
        roundsPartial: 31,
      });
      const sponge = poseidon.poseidonSponge({
        Fp,
        rate,
        capacity,
        sboxPower: 17,
        mds,
        roundConstants,
        roundsFull: 8,
        roundsPartial: 31,
      });
      const inputs = [
        3801852864665033841774715284518384682376829752661853198612247855579120198106n,
        8354898322875240371401674517397790035008442020361740574117886421279083828480n,
        4810388512520169167962815122521832339992376865086300759308552937986944510606n,
        6901184695964460143517399399785179769303979738604374595034454667750561389951n,
        4569986992907167903298094880801044988451682407606958090985246015539197576880n,
        1659013762488693582855478522957329119959921484276233144739847127722099836592n,
        5873855434568679481242703448145783278614510745576299549051743569349492512978n,
        8126778056340108742720298710864854335340160587591670858399923536543205675034n,
        7146400424093292796305326969877508376475248301146079897262686723570477471481n,
        4313136198840596462591029581810482612339281338296848099835538102215716458507n,
        6282620155184535925059193831765937196673297460411024331501133151513540140819n,
      ];
      const s1 = sponge();
      s1.absorb(inputs.slice(0, 3));
      eql(s1.squeeze(2), [
        25283854350347435274635030330108075556936659978586145851296361714414722574977n,
        28603365815395435865415304087135297453074687980742616616978979944696141627335n,
      ]);
      // absorb(0);squeeze(3);
      const s2 = sponge();
      s2.absorb([]);
      eql(s2.squeeze(3), [
        22095061030825764236545407651195963259093673160236850179062763631622849581041n,
        51147331969562634030541262163015923329074972559171117523202343735176539631092n,
        38566017764735118620833500678934515124800416244503159365750257744180372818350n,
      ]);
      // absorb(11);squeeze(2);
      const s5 = sponge();
      s5.absorb(inputs);
      eql(s5.squeeze(2), [
        16566857174767620685802510376201107449033507070456217544270378314684407453695n,
        449661346404481260654646786033891474020700499604872754349019325201507701381n,
      ]);
      // absorb(3);squeeze(2);absorb(0);squeeze(2)
      const s9 = sponge();
      s9.absorb(inputs.slice(0, 3));
      eql(s9.squeeze(2), [
        25283854350347435274635030330108075556936659978586145851296361714414722574977n,
        28603365815395435865415304087135297453074687980742616616978979944696141627335n,
      ]);
      s9.absorb([]);
      eql(s9.squeeze(2), [
        49166328828518411259658775292174876194897505808260003840078267783408303626061n,
        11687729391556811786970896353500121413690369995764901343770077126146977132960n,
      ]);
    });
  });
});

should.runWhen(import.meta.url);
